package org.zhadoop.stream.cql.mapping;

import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zhadoop.streaming.serde.CSVSerDe;
import org.zhadoop.streaming.serde.SimpleSerDe;
import org.zhadoop.streaming.serde.StreamSerDe;

import com.google.common.base.Strings;
import com.google.common.collect.Maps;

/**
 * CQL 内置的输入流和输出流简写映射
 * <p/>
 * 不区分大小写
 * @author zwd
 *
 */
public enum SimpleLexer {
	
	INPUT(){
		private final Map<String,String> INPUTOPERATOR_MAPPING = Maps.newConcurrentMap();
		
		@Override
		public String getSimpleName(String fullName) {
			return baseGetSimpleName(fullName, INPUTOPERATOR_MAPPING);
		}

		@Override
		public String getFullName(String fullName) {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		protected boolean register(String simpleName, Class<?> clazz) {
			// TODO Auto-generated method stub
			return false;
		}

		@Override
		protected boolean unRegister(String simpleName) {
			// TODO Auto-generated method stub
			return false;
		}
		
	},
	
	SERDE() {
		private final Map<String,String> SERDE_MAPPING = Maps.newConcurrentMap();
		
		@Override
		public String getSimpleName(String fullName) {
			return baseGetSimpleName(fullName,SERDE_MAPPING);
		}

		@Override
		public String getFullName(String simpleName) {
			return baseGetFullName(simpleName, SERDE_MAPPING);
		}

		@Override
		protected boolean register(String simpleName, Class<?> clazz) {
			return baseRegister(simpleName, clazz, SERDE_MAPPING);
		}

		@Override
		protected boolean unRegister(String simpleName) {
			return baseUnRegister(simpleName,SERDE_MAPPING);
		}
	};
	
	private static final Logger LOG = LoggerFactory.getLogger(SimpleLexer.class);
	
	/**
	 * 通过全称获取简称，如果不存在，返回null
	 * @param fullName
	 * @return
	 */
	public abstract String getSimpleName(String fullName);
	
	
	/**
	 * 获取全称，如果不存在，返回null
	 * @param fullName
	 * @return
	 */
	public abstract String getFullName(String simpleName);
	
	
	/**
	 * 注册简称，
	 * 注意，注册可能会导致系统注册变量的丢失，即使后面移除了注册，也不会恢复
	 * @param simpleName
	 * @param clazz
	 * @return
	 */
	protected abstract boolean register(String simpleName,Class<?> clazz);
	
	/**
	 * 移除注册，如果返回false，移除失败，说明简称不存在
	 * @param simpleName
	 * @return
	 */
	protected abstract boolean unRegister(String simpleName);
	
	static{
		//序列化反序列化类
		registerSerDe("SimpleSerDe", SimpleSerDe.class);
		registerSerDe("CsvSerDe", CSVSerDe.class);
	}
	
	/**
	 * 注册序列化类/反序列化的类的简称
	 * 由于没有办法区分哪些是系统注册，哪些是用户注册的，所以默认后注册的覆盖先注册的
	 * 由于泛型对注册进行限制，方式注册错误类，这样就可以在编译时期发现问题
	 * @param name
	 * @param clazz
	 */
	public static void registerSerDe(String name, Class<? extends StreamSerDe> clazz) {
		SERDE.register(name, clazz);
	}

	
	private synchronized static String baseGetSimpleName(String fullName, Map<String, String> mapping) {
		if(fullName == null){
			return null;
		}
		
		for(Map.Entry<String, String> et: mapping.entrySet()){
			if(fullName.equals(et.getValue())){
				return et.getKey();
			}
		}
		return null;
	}

	private synchronized static String baseGetFullName(String simpleName, Map<String, String> mapping) {
		if(Strings.isNullOrEmpty(simpleName)){
			return null;
		}
		
		for(Map.Entry<String, String> et : mapping.entrySet()){
			if(simpleName.equalsIgnoreCase(et.getKey())){
				return et.getValue();
			}
		}
		return null;
	}


	private synchronized static boolean baseRegister(String simpleName, Class<?> clazz, Map<String, String> mapping) {
		if(Strings.isNullOrEmpty(simpleName) || clazz == null){
			LOG.warn("Failed to regisiter simple lexer mapping, name or class is null");
			return false;
		}
		
		LOG.info("register simple lexer {}, class {}.",simpleName,clazz);
		if(mapping.containsKey(simpleName)){
			LOG.warn("Exists simple lexer {} will be replaced.",simpleName);
		}
		mapping.put(simpleName, clazz.getName());
		return true;
	}
	
	//加同步防止多线程同时添加或者删除导致的错误，虽然说map本身是同步的，但是方法并不同步
	private synchronized static boolean baseUnRegister(String name, Map<String, String> mapping) {
		if(Strings.isNullOrEmpty(name)){
			LOG.warn("Failed to unRegister simple lexer mapping, name is null");
			return false;
		}
		
		//由于可能移除系统注册的简称，所有这里级别为warn
		LOG.warn("UnRegister '{}' from simple lexers.",name);
		if(mapping.containsKey(name)){
			mapping.remove(name);
		}
		return true;
	}
	
	

	
	
	
}
